﻿using Rhino;
using Rhino.Display;
using Rhino.DocObjects;
using Rhino.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;

namespace AiMoCore
{
    partial class GHCSharpScriptInstance
    {
        #region Point3d
        /// <summary>
        /// 将Point3d点添加到Rhino中
        /// </summary>
        public Guid Bake(Point3d geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将Point3f点添加到Rhino中
        /// </summary>
        public Guid Bake(Point3f geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将PointCloud点云添加到Rhino中
        /// </summary>
        public Guid Bake(PointCloud geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }

        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<Point3d> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Point3d> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<Point3f> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Point3f> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        public Guid[] Bake(IEnumerable<PointCloud> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<PointCloud> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region Line
        public Guid Bake(Line geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<Line> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Line> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region Box
        public Guid Bake(Box geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<Box> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Box> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region BoundingBox
        public Guid Bake(BoundingBox geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<BoundingBox> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<BoundingBox> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region Circle
        public Guid Bake(Circle geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<Circle> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Circle> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region Arc
        public Guid Bake(Arc geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<Arc> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Arc> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region Ellipse
        public Guid Bake(Ellipse geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<Ellipse> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Ellipse> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region Cone
        public Guid Bake(Cone geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<Cone> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Cone> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region Rectangle3d
        public Guid Bake(Rectangle3d geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<Rectangle3d> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Rectangle3d> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region Polyline
        public Guid Bake(Polyline geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<Polyline> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Polyline> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region Cylinder
        public Guid Bake(Cylinder geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<Cylinder> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Cylinder> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region Plane
        public Guid Bake(Plane geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<Plane> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Plane> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region Sphere
        public Guid Bake(Sphere geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<Sphere> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Sphere> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region GeometryBase
        public Guid Bake(GeometryBase geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<GeometryBase> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<GeometryBase> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region RhinoObject
        public Guid Bake(RhinoObject geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }
        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<RhinoObject> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<RhinoObject> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region Text


        public Guid Bake(string text, Point3d location, int height = 12, ObjectAttributes objectAttributes = null)
        {
            TextDot textDot = new TextDot(text, location)
            {
                FontHeight = height,
            };
            return BakeOne(textDot, objectAttributes);
        }
        public Guid Bake(string text, Plane plane, double height = 12, ObjectAttributes objectAttributes = null)
        {
            Text3d text3D = new Text3d(text, plane, height)
            {
                HorizontalAlignment = TextHorizontalAlignment.Center,
                VerticalAlignment = TextVerticalAlignment.Middle,
            };
            return BakeOne(text3D, objectAttributes);
        }
        public Guid Bake(Text3d geo, ObjectAttributes objectAttributes = null)
        {
            return BakeOne(geo, objectAttributes);
        }


        /// <summary>
        /// 将多个物体添加到Rhino中
        /// </summary>
        public Guid[] Bake(IEnumerable<Text3d> geos)
        {
            return BakeMulti(geos);
        }
        public Guid[] Bake(IEnumerable<Text3d> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            return BakeMulti(geos, objectAttributes);
        }
        #endregion

        #region BakeBase
        Guid[] BakeMulti<T>(IEnumerable<T> geos, IEnumerable<ObjectAttributes> objectAttributes)
        {
            List<Guid> result = new List<Guid>();
            T[] arrayGeos = geos.ToArray();
            ObjectAttributes[] arrayAttr = objectAttributes.ToArray();
            if (arrayAttr.Length == arrayGeos.Length)
            {
                for (int i = 0; i < arrayAttr.Length; i++)
                {
                    Guid id = BakeOne(arrayGeos[i], arrayAttr[i]);
                    if (id != Guid.Empty) result.Add(id);
                }
            }
            return result.ToArray();
        }

        Guid[] BakeMulti<T>(IEnumerable<T> geos)
        {
            List<Guid> result = new List<Guid>();
            foreach (T geo in geos)
            {
                Guid id = BakeOne(geo, null);
                if (id != Guid.Empty) result.Add(id);
            }
            return result.ToArray();
        }

        Guid BakeOne<T>(T geo, ObjectAttributes objectAttributes)
        {
            switch (geo)
            {
                case Point3d pt:
                    if (pt.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddPoint(pt, objectAttributes);
                    break;
                case Point3f ptf:
                    if (ptf.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddPoint(ptf, objectAttributes);
                    break;
                case PointCloud ptCloud:
                    if (ptCloud.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddPointCloud(ptCloud, objectAttributes);
                    break;
                case Line line:
                    if (line.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddLine(line, objectAttributes);
                    break;
                case Box box:
                    if (box.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddBox(box, objectAttributes);
                    break;
                case BoundingBox bbox:
                    if (bbox.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddBox(new Box(bbox), objectAttributes);
                    break;
                case Circle circle:
                    if (circle.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddCircle(circle, objectAttributes);
                    break;
                case Arc arc:
                    if (arc.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddArc(arc, objectAttributes);
                    break;
                case Ellipse ellipse:
                    if (ellipse.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddEllipse(ellipse, objectAttributes);
                    break;
                case Cone cone:
                    if (cone.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddSurface(cone.ToNurbsSurface(), objectAttributes);
                    break;
                case Rectangle3d rectangle:
                    if (rectangle.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddRectangle(rectangle, objectAttributes);
                    break;
                case Polyline polyline:
                    if (polyline.IsValid && polyline.Count > 1)
                        return RhinoDoc.ActiveDoc.Objects.AddPolyline(polyline, objectAttributes);
                    break;
                case Cylinder cylinder:
                    if (cylinder.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddBrep(cylinder.ToBrep(true, true), objectAttributes);
                    break;
                case Plane plane:
                    return BakePlane(plane, objectAttributes);
                case Sphere sphere:
                    if (sphere.IsValid)
                        return RhinoDoc.ActiveDoc.Objects.AddSphere(sphere, objectAttributes);
                    break;
                case GeometryBase geometry:
                    return BakeGeometry(geometry, objectAttributes);

                case RhinoObject rhinoObject:
                    if (objectAttributes == null)
                        objectAttributes = rhinoObject.Attributes;
                    if (rhinoObject is InstanceObject instanceObject)
                        return RhinoDoc.ActiveDoc.Objects.AddInstanceObject(instanceObject.InstanceDefinition.Index, instanceObject.InstanceXform, objectAttributes);
                    else
                        return RhinoDoc.ActiveDoc.Objects.Add(rhinoObject.Geometry, objectAttributes);
                case Text3d text3D:
                    return RhinoDoc.ActiveDoc.Objects.AddText(text3D, objectAttributes);
            }
            return Guid.Empty;
        }

        Guid BakeGeometry(GeometryBase geometry, ObjectAttributes objectAttributes)
        {
            if (geometry.IsValid)
                return RhinoDoc.ActiveDoc.Objects.Add(geometry, objectAttributes);
            else
            {
                switch (geometry)
                {
                    case Mesh mesh:
                        return RhinoDoc.ActiveDoc.Objects.AddMesh(mesh, objectAttributes, null, false, false);

                    case Brep brep:
                        return RhinoDoc.ActiveDoc.Objects.AddBrep(brep, objectAttributes, null, false, false);

                    default:
                        return RhinoDoc.ActiveDoc.Objects.Add(geometry, objectAttributes);

                }
            }
        }

        Guid BakePlane(Plane plane, ObjectAttributes objectAttributes)
        {
            Point3d pt = RhinoDoc.ActiveDoc.Views.ActiveView.ActiveViewport.CameraTarget;
            RhinoDoc.ActiveDoc.Views.ActiveView.ActiveViewport.GetWorldToScreenScale(pt, out double pixelPerUnit);
            double s = 40 / pixelPerUnit;
            Polyline pl = new Polyline(10)
            {
                plane.PointAt(0,0,s),
                plane.Origin,
                plane.PointAt(s,0,0),
                plane.Origin,
                plane.PointAt(0,s,0),
                plane.PointAt(s,s,0),
                plane.PointAt(s,-s,0),
                plane.PointAt(-s,-s,0),
                plane.PointAt(-s,s,0),
                plane.PointAt(0,s,0)
            };
            return RhinoDoc.ActiveDoc.Objects.AddPolyline(pl, objectAttributes);
        }

        #endregion

    }
}
